<?php 
#using ('Origami_Configuration_Settings');
using ('News_Usenet_NNTP');
using ('News_Usenet_Group');
#using ('Origami_XML_Reader');
define ('GROUP_LIST_URI', './server-groups-list.ini');

function cmp($a, $b) {
    return ($a->get_attribute('name') < $b->get_attribute('name')) ? -1 : 1;
}

class News_Usenet_Server
{
    var $Server;
    var $Username;
    var $Password;
    var $Groups;
    var $Db;
    var $NNTP;
    var $Controller;
    var $List = array();
    var $groupName;
    var $groupData;
    function News_Usenet_Server($controller)
    { 
        $this->Controller = $controller;
        $this->groupName  = $this->Controller->Settings['group']; 
        $this->groupData  = array();
        $info = array ( 'server'  =>"news.usenet.net",
                        'username'=>'info@cyber8.net',
                        'password'=>'Password' );
        $this->Server     = $info['server'];
        $this->Username   = $info['username'];
        $this->Password   = $info['password'];
        $this->Db         = array(); //new Origami_XML_Reader();  
        $this->NNTP       = new News_Usenet_NNTP($this->Server, trim($this->Username), trim($this->Password));   
    }

    function LoadNewsGroup ($numOfArticles = 0, $first = NULL)
	{ 
        $this->List = array();
        $nntp = $this->NNTP;
        if (!$nntp->connect())                                                
        {                                                
            header("Content-Error: " . $nntp->get_error_message());                                               
            echo "<b>".$messages_ini["error"]["nntp_fail"]."</b><br>";                                                
            echo $nntp->get_error_message().$nntp_server."<br>";                                                
            return;                                               
        }  
        
        if ( $gi=$nntp->join_group(trim($this->groupName)) )                                               
        {                                      
            $minimum    = $gi['start_id'];                               
            $maximum    = $gi['end_id'];                                 
            $start_id   = min ($minimum, $maximum);                        
            $max_id     = max ($minimum, $maximum);     
		    $start_page = $start_id; 
            
		    $end_id     = $start_id + $numOfArticles;
		    
		    
            $this->groupData = array('min'=>$start_id, 'max'=>$max_id); 
		    
		    if ($first) $start_id = $first + 1;
          
		    
            $nntp_query = "XOVER " . $start_id . "-" . $max_id;   
            

            
            $buf        = $nntp->send_request( $nntp_query );                                                   
            $response   = $nntp->parse_response($buf);         
		    $cursor		= 0;
		    $xml        = '';
		   
            if ($response["status"] == ARTICLE_OVERVIEW || $response["status"] == ARTICLE_HEAD)                                                
            {   
                                                          
                $buf = fgets($nntp->nntp, 4096);   
                 
                while (!preg_match("/^\.\s*$/", $buf))                                                
                {    
                    #echo $buf;
	                $art = new News_Usenet_Article($buf, 0, $this->Controller->Settings['group']);
	
	                if (array_key_exists($art->regEx, $this->List))
	                {
	                    if (array_key_exists($art->partKey, $this->List[$art->regEx]))
	                    {
	                        $this->List[$art->regEx][$art->partKey][] = $art;
	                    }
	                    else
	                    {
	                        $this->List[$art->regEx][$art->partKey] = array($art);
	                    }
	                }
	                else
	                {
	                    $this->List[$art->regEx] = array($art->partKey => array($art));
	                }                 
	                
                    $cursor ++;
                    if ($cursor >= $numOfArticles)  break;
                    if ($cursor % 1000 == 0)   $this->Controller->LogEntry ("Retrieving group information...", $cursor, $numOfArticles, $this->groupName);
                    
                    $buf = fgets($nntp->nntp, 4096);     
                }              
            }
        }                        
        $nntp->quit();     
        return $this->Collate ();		
	}
    
    
	function _SearchNewsGroup ($param = NULL, $start = NULL, $end = NULL, $thread = NULL)
	{
		echo $param . ',' . $start . ',' . $end;
		$nntp = $this->NNTP;
		$file = $start ? "data/{$this->groupName}{$start}.dat" : "data/{$this->groupName}.dat";

        
		
		$fp   = fopen ($file, 'a');
		
        if (!$nntp->connect())                                                
        {                                                
            header("Content-Error: " . $nntp->get_error_message());                                               
            echo "<b>".$messages_ini["error"]["nntp_fail"]."</b><br>";                                                
            echo $nntp->get_error_message().$nntp_server."<br>";                                                
            return;                                               
        }   
		
        echo "Searching group {$this->groupName} for '$param'\n"; 
        if ( $gi=$nntp->join_group(trim($this->groupName)) )                                               
        {
        	if ($param) $param = strtolower($param);                                     
            $minimum    = $gi['start_id'];                               
            $maximum    = $gi['end_id'];                                 
            $start_id   = $start ? $start : min ($minimum, $maximum);                        
            $max_id     = $end   ? $end   : max ($minimum, $maximum);  
            $size       = $max_id - $start_id;
		    $count      = 0;
		    $span       = floor ($size / 25);
            $nntp_query = "XOVER {$start_id}-{$max_id}";    
            $buf        = $nntp->send_request( $nntp_query );                                                   
            $response   = $nntp->parse_response($buf);   
	        echo "Searching $size articles\n"; 
	        echo "$nntp_query\n"; 
	        echo "$buf\n"; 
            $this->Controller->LogEntry ("Retrieving group information...", $count, $size, $this->groupName);
            if ($response["status"] == ARTICLE_OVERVIEW || $response["status"] == ARTICLE_HEAD)                                                
            {                                         
                $buf = fgets($nntp->nntp, 4096);    
                while (!preg_match("/^\.\s*$/", $buf))                                                
                {
                	if ($param == NULL || strpos(strtolower($buf), $param))
					{
                	    fputs($fp, $buf); 
					}   
				    $count ++;
					if ($count % 25000 == 0)
					{
						$sz = filesize($file); echo sprintf("Retrieving $sz bytes %s %s...\n", $count, $size);
						$this->Controller->LogEntry ("Retrieving $sz bytes $start_id $max_id...", $count, $size, $this->groupName, $thread);
					} 
                    $buf = fgets($nntp->nntp, 4096);     
                }   
                $this->Controller->LogEntry ("Retrieving $sz bytes $start_id $max_id...", $count, $size, $this->groupName, $thread);           
            }
        }                        
        $nntp->quit();     
		fclose ($fp); 
		unset ($fp);
		return $file; 	
	} 

    function Run($Command, $Priority = 0)
    {
    	unlink ("cmd-{$Priority}.out"); 
        $PID = shell_exec("nohup $Command 1> cmd-{$Priority}.out & echo $!");
        return($PID);
    }

    function IsRunning($PID)
    {
        exec("ps $PID", $ProcessState);
        return(count($ProcessState) >= 2);
    }
	    
	function SearchThreaded ($param = NULL)
	{
		$nntp   = $this->NNTP; 
		$time   = time();
		$thread = array(); 
        if (!$nntp->connect())                                                
        {                                                
            header("Content-Error: " . $nntp->get_error_message());                                               
            echo "<b>".$messages_ini["error"]["nntp_fail"]."</b><br>";                                                
            echo $nntp->get_error_message().$nntp_server."<br>";                                                
            return;                                               
        }  
		
        echo "Getting info for group {$this->groupName}\n"; 
        if ( !( $gi=$nntp->join_group(trim($this->groupName)) ))                                               
        {
        	echo "Unable to join group.\n";
		}            
        $nntp->quit();   
		
		print_r ($gi);
		
		$min   = min ($gi['start_id'], $gi['end_id']);                  
        $max   = max ($gi['start_id'], $gi['end_id']);             
		$span  = ceil(($max - $min) / 4);
		$tmp   = array ();
		
        for ($i=$min;$i<$max;$i+=$span)
        {
            $tmp[] = array('x'=>$i, 'y'=>$i + $span - 1); 
        }
        
		print_r ($tmp);
         
        for ($i=0;$i<sizeof($tmp);$i++)
        { 
            $command  = "php index.php as {$this->groupName} {$param} " . $tmp[$i]['x'] . " " . $tmp[$i]['y'] . " " . $i;
            echo $command . "\n";
            $thread[] = $this->Run ($command, $i);
        }
        
        while (true)
        {
			 $run = false;
			 for ($i=0;$i<sizeof($thread);$i++)
			 {
			     $run = $run || $this->IsRunning($thread[$i]);
				 // echo $thread[$i] . "\n";
			 }
			 $elapsed = time() - $time; 
			 // echo "($elapsed).\n";
			 // $this->Controller->LogEntry ("{$elapsed}. Checking thread", 1, 1, $this->groupName);
			 sleep(2);
			     
			 if (!$run) break;
        }  
		
		$file = "data/{$this->groupName}.dat";
		$fp = fopen ($file, 'a');
        for ($i=0;$i<sizeof($tmp);$i++)
        {
        	$hook = "data/{$this->groupName}" . $tmp[$i]['x'] . ".dat";
			if (file_exists($hook))
			{
				$frag = $this->Controller->Read ($hook);
				fputs($fp, $frag); 
				unlink($hook);
			}
        }
		fclose ($fp);
		
		if (file_exists(THREAD_FILE)) unlink(THREAD_FILE);
		$this->Controller->Thread->Clear();
		
		return $this->Assemble($file);
	}
    
    
	function Assemble ($file)
	{ 
		$fp   = fopen($file, 'r');   
		$size = filesize($file);   
                 
        echo "Download of {$size} bytes complete. Collating...\n"; 
        while (($buf = fgets($fp, 4096)) !== false)                                                
        {    
            $art = new News_Usenet_Article($buf, 0, $this->groupName);
	        if (array_key_exists($art->regEx, $this->List))
	        {
	            if (array_key_exists($art->partKey, $this->List[$art->regEx]))
	            {
	                $this->List[$art->regEx][$art->partKey][] = $art;
	            }
	            else
	            {
	                $this->List[$art->regEx][$art->partKey] = array($art);
	            }
	        }
	        else
	        {
	            $this->List[$art->regEx] = array($art->partKey => array($art));
	        }     
			unset ($art);                 
        }              
        fclose ($fp);
	    unlink ($file);
        return $this->Collate ();	
	}
    
    
	function SearchNewsGroup ($param = NULL, $start = NULL, $end = NULL)
	{
		$file = $this->_SearchNewsGroup($param, $start, $end); 
		return $this->Assemble($file);
	} 
 
	function Collate ()
	{
		
        $step = 500;
        $xml  = array();
        $xml[] = '<?xml version="1.0" encoding="ISO-8859-1"?>';
        $xml[] = '<list groupname="' . $this->groupName . '">';
        $cnt = 0;
       
          
        while (list($name, $item) = each($this->groupData))
        {
            $xml[] = "<{$name}>{$item}</{$name}>";
        }
          
        
        while (list($name, $item) = each($this->List))
        { 
            $box  = array(); 
            $post = array(); 
                   
            while (list($key, $cluster) = each($item))
            { 
                $ext     = array();
                $rar     = NULL;
                $first   = $cluster[0]; 
                $picture = preg_match ('/\.(jpg|jpeg|png|gif|bmp)/i', $first->Subject);
                $video   = preg_match ('/\.(m4v|flv|mpeg|mpg|mov|wmv|avi|mkv)/i', $first->Subject, $ext);
                $picture = $picture && !preg_match ('/(par2|RE\:)/i', $first->Subject);
                $video   = $video && !preg_match ('/(par2|RE\:|\.\d{3})/i', $first->Subject) && !$picture;
                if (!$video)
                {
                    $rar     = preg_match ('/\.(rar|r\d{2})/i', $first->Subject, $ext);
                    $rar     = $rar && !preg_match ('/(par2|RE\:|\.\d{3})/i', $first->Subject);
                }
                $picture = $picture && !$video && !$rar;
              
                if ($picture || $video || $rar)
                {
                    $post[] = $cluster;
                } 
            } 
         
            if (sizeof($post) > 0)
            {
                 $id    = $this->_getId($post[0]);     
                 $ref   = $post[0][0]->Ref;              
                 $text  = $post[0][0]->Subject;        
                 $from  = $post[0][0]->From;
                 $date  = $post[0][0]->articleDate;
                 $enum  = $this->Controller->GetType ($text);
                 $type  = $enum == TYPE_IMAGE ? 'picture' : $ext[1];
                 $type  = $enum == TYPE_MOVIE ? 'wmv' : $type;
                 $type  = $enum == TYPE_RAR   ? 'rar' : $type;
                 $type  = $ext[1] == 'm4v' || $ext[1] == 'mp4'   ? 'm4v' : $type;
                 $subj  =  iconv("ISO-8859-1", "UTF-8", $text); 
                 $xml[] = '    <article index="' . $cnt . '">';       
                 $xml[] = '        <id><![CDATA[' . $id . ']]></id>';   
                 $xml[] = '        <type>'.$type.'</type>';    
                 $xml[] = '        <name><![CDATA[' . htmlentities ($from['name']) . ']]></name>';  
                 $xml[] = '        <email><![CDATA[' . htmlentities ($from['email']) . ']]></email>'; 
                 $xml[] = '        <date><![CDATA[' . $date . ']]></date>';   
                 $xml[] = '        <subject><![CDATA[' . htmlentities ($subj) . ']]></subject>';  
                 $xml[] = '        <ref><![CDATA[' . htmlentities (utf8_encode( implode('|', $ref) )) . ']]></ref>';   
                 $xml[] = '        <items>';     
                 for ($i=0;$i<sizeof($post);$i++)
                 {
                     $id    = $this->_getId($post[$i]);       
                     $text  = $post[$i][0]->Subject;
                     $subj  =  iconv("ISO-8859-1", "UTF-8", $text); 
	                 $xml[] = '            <article>';       
	                 $xml[] = '                <id><![CDATA[' . $id . ']]></id>';   
	                 $xml[] = '                <subject><![CDATA[' . htmlentities ($subj) . ']]></subject>';  
	                 $xml[] = '            </article>';       
                 }
                 $xml[] = '        </items>';      
                 $xml[] = '    </article>';     
                 $cnt ++;
             }   
        }  
        $xml[] = '</list>'; 
        
        return implode ("\n", $xml);
        
	}
	
     function _getId ($cluster)
     {
        $ret = array();
        $srt = array();

        for ($i=0;$i<sizeof($cluster);$i++)
        { 
            if (sizeof($cluster) > 1 && preg_match('/\((\d+)\/(\d+)\)/', $cluster[$i]->Subject, $matches))
            {
                $num = $matches[1];
                $cnt = $matches[2]; 
                $ret[$num - 1] = $cluster[$i]->messageId; 
            }
            else
            { 
                $ret[] = $cluster[$i]->messageId;
            }
        }
        $value = array();
        for ($i=0;$i<sizeof($ret);$i++) 
        {
            if (isset($ret[$i]))
            {
                $value[] = $ret[$i];
            }
        } 
        return implode('-', $value);
     }            

    function getGroupList()
    {  
       if (!file_exists(GROUP_LIST_URI))
       {
            $this->_updateGroupList();
       }
        $this->Open (GROUP_LIST_URI); 
    }
    
    function Open ($path)
    {
         $this->Db = array(); 
        
        $xml = simplexml_load_file(GROUP_LIST_URI);
        $result = $xml->children();
        for($x=0;$x<sizeof($result);$x++)
        {
            $group=$result[$x];
           // var_dump($group->attributes());
            $this->Db[] = $group; 
           // break;
        }
       // exit;
    }
    
    function Display()
    { 
       // $mgr = new News_Application_CacheManager($this->Controller);
        if (!$this->Controller->Factory) return;
        
        $my = $this->Controller->GetSubscribedGroups ();  
        $sp = $this->Controller->Settings['sp']; 
		
        $data   = array(); 
        $data['onload']   = 'splash';
        
	    $data['toolbar']  = $this->Controller->Factory->TabBar('Server'); 
        $data['toolbar'] .= "<div style='float:right'>";
        $data['toolbar'] .= "<form method='post'>";
        $data['toolbar'] .= sprintf("<input name='sp' value='%s'/>", $sp);
        $data['toolbar'] .= "<input type='submit' value='Find'>"; 
        $data['toolbar'] .= "</form>";
        $data['toolbar'] .= "</div>"; 
        
		$page  = $this->Controller->Settings['page'];
	    if (strlen($page) == 0) $page = 1; 
//        echo sys_get_temp_dir();
        
        if (strlen($sp)==0)
        {
            $media = new News_UI_Media($this->Controller);
            $list  = $media->Collate(true);
            $m4v   = NULL; $x = 0;
            while (!$m4v && ++$x < 100)
            {
       	        $m4v = $list[rand(0, sizeof($list) - 1)];  
            } 
            $uri   = array('ui'=>'home', 'page'=>NULL);
            
//            Wonder wall
            $data['main'] .= "<div style='width:732px;text-align:center;float:left' align='center'>";
	        for ($i=0;$i<sizeof($my) && $i < 6;$i++)
	        {
	            $value = $my[$i]; 
	            $data['main'] .= "<div class='home'><img src='/images/clear.gif' id='box{$i}' border='0'/></div>";
	        } 
		    $hi     = $page * UI_PAGE_SIZE;
		    $low    = $hi - UI_PAGE_SIZE;
            $data['main'] .= "</div>";
            
//            Media floater
            $data['main'] .= "<div style='float:left; font-size:9pt;width:290px;padding:0px;'>";
            
            if ($m4v)
            {	        
	            $data['main'] .= "<div class='bullet'><b>Media</b></div>";
		        
		        $data['main'] .= "<div class='bullet' style='height:210px;overflow:hidden'>"; 
	            $data['main'] .= $this->Controller->Factory->VideoPlayer($m4v['name'], 240, 160);
	            $data['main'] .= sprintf('<div align="center"><b><a href="/ui/commandhandler/request/group/group/%s">%s</a></b></div>', $m4v['group'], $m4v['group']);
	            $data['main'] .= "</div>";
		        
	            $data['main'] .= "</div>";
            }
            
//            Grouplist floater
            $data['main'] .= "<div style='float:left; font-size:9pt;width:290px;padding:0px;'>";//<b>Subscribed Groups</b><hr noshade/>";
	        $data['main'] .= "<div class='bullet'><b>Subscribed groups</b></div>"; 
	        for ($i=0;$i<sizeof($my);$i++)
	        {
	            $value = $my[$i];  
		        $data['main'] .= "<script language='javascript'>db.push('{$value}');</script>"; 
	        } 
	        for ($i=$low;$i<sizeof($my)&&$i<$hi;$i++)
	        {
	            $value = $my[$i]; 
		        // $a=array ('/alt/','/binaries/','/picture/','/erotic/','/nospam/','/multimedia/');
	        	// $b=array ('a','b','p','e','ns','mm'); 
		        $caption = $this->Controller->GroupRename($value); //preg_replace($a, $b, $value);  
	            $data['main'] .= "<div class='bullet'>&bull; <a href='/ui/commandhandler/request/group/group/{$value}'>{$caption}</a></div>"; 
	        } 
            $data['main'] .= "<div class='bullet'>" . $this->Controller->Factory->Paginator(sizeof($my), $uri) . "</div>"; 
            $data['main'] .= "</div>";
        }
        else
        {
            $this->getGroupList();
       
            $data['main'] .= "<table>";
	        for ($i=0;$i<sizeof($this->Db);$i++)
	        {  
	            $att = $this->Db[$i]->attributes();
	            $id  = $att['name'];
	            $num = $att['count'];
	            
	            if ($num < 1000) continue;
	            
	            if (strpos(strtolower($id), strtolower($sp)) !== false)
	            { 
			        $data['main'] .= "<tr>"; 
			        foreach($this->Db[$i]->attributes() as $name => $value) 
			        { 
			            if ($name == 'name')
			            {
		                    $css = array_search ($value, $my) !== false ? ' style="font-weight:bold;color:gray;" ' : '';
		                    $data['main'] .= "<td><a {$css} href='/ui/commandhandler/request/group/group/{$value}'>{$value}</a></td>";
			            }
			            else
			            {
			                $data['main'] .= "<td>{$value}</td>";
			            }   
			        }
			        $data['main'] .= "</tr>"; 
	            } 
            }
       
            $data['main'] .= "</table>";
        }
        
        $data['main'] .= "</div>"; 
		echo $this->Controller->Structure ($data);
//        echo "</body>"; 
        return; 
    }
    
    
    function _updateGroupList()
    {
        $this->Db = array();
        $out = array();
        if (!$this->NNTP->connect())                                                  
        {                                                                                                 
            header("Content-Error: " . $this->NNTP->get_error_message());                                                 
            echo $nntp_server."!<b>".$messages_ini["error"]["nntp_fail"]."</b><br>";                                                  
            echo "Error: " . $this->NNTP->get_error_message()."<br>";                                                  
        }                                                  
        else                                                 
        {                                                                
            $buf       = $this->NNTP->send_request("list active");                                                  
            $response  = $this->NNTP->parse_response($buf);                                                   
            $buf       = fgets($this->NNTP->nntp, 4096);                                                  
            $ret       = array();                                                  
                                                  
            while (strlen($buf) > 0)                                                  
            {                                                   
                if (trim($buf)==".")                                                 
                {                                                  
                    break;                                                 
                }                                                 
                $arr  = explode (" ", $buf);                             
				if (preg_match('/alt\.binaries(.*)/',$arr[0]))                                             
				{ # echo $buf;    		              
				    $numBegin  = $arr[1];
				    $numEnd    = $arr[2];
					$groupname = htmlentities( str_replace("'","&apos;",$arr[0]) );     
					$group     = new News_Usenet_Group($groupname, $numBegin, $numEnd);	 	
					$this->Db[] = array('name'=>$groupname, 'begin'=>$numBegin, 'end'=>$numEnd); 		         
					$out[] = $group->Serialize(); //"db[]=array(name=>{$groupname},begin=>{$numBegin},end=>{$numEnd})";                             
				}                                               
                $buf  = fgets($this->NNTP->nntp, 4096);    
            }                                                  
        }                                 
        $this->NNTP->quit();  
        $markup = sprintf("<groups>%s</groups>", implode('', $out));
        $fp = fopen(GROUP_LIST_URI, 'w');
        if ($fp)
        {
            fwrite ($fp, $markup);
            fclose($fp);
            return;
        }
        echo "Could not open <b>{GROUP_LIST_URI}</b>";
        #$this->Db->OpenMem($markup);
        #$this->Db->Save(GROUP_LIST_URI);        
    }    
}
